/*****************************************************************************
Copyright 2006 Kervin L. Pierre
    EMAIL: otlkcon@adevsoft.com

This file is part of Otlkcon.

Otlkcon is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

Otlkcon is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Otlkcon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*******************************************************************************/

#include "stdafx.h"
#include "otlkcon_memory.h"

otlkcon_memory::otlkcon_memory(LPALLOCATEBUFFER lb, LPALLOCATEMORE lm , LPFREEBUFFER lf)
{
    this->lpAllocateBuffer = lb;
    this->lpAllocateMore = lm;
    this->lpFreeBuffer = lf;
}

otlkcon_memory::otlkcon_memory( otlkcon_memory *memObj )
{
    this->lpAllocateBuffer = memObj->lpAllocateBuffer;
    this->lpAllocateMore = memObj->lpAllocateMore;
    this->lpFreeBuffer = memObj->lpFreeBuffer;
}

otlkcon_memory::~otlkcon_memory()
{
    ;
}

void *otlkcon_memory::malloc( ULONG size )
{
    LPVOID result = NULL;

    // FIXME: In all the malloc() routines we need to have
    //        a 'size' sanity check.  If this size is
    //        exceeded, we should at least log that somewhere
    if( lpAllocateBuffer(size, &result ) != S_OK )
    {
        DebugBreak();
    }
    memset(result,0,size);

    if( result == 0 )
    {
        DebugBreak();
    }

    return result;
}
 
void *otlkcon_memory::mallocMore( void *obj, ULONG size )
{
    LPVOID result = NULL;

    if( lpAllocateMore( size, obj, &result ) != S_OK )
    {
        DebugBreak();
    }
    memset(result,0,size);

    if( result == 0 )
    {
        DebugBreak();
    }

    return result;
}

void otlkcon_memory::free( void *buff )
{
    lpFreeBuffer( buff );
}

char *otlkcon_memory::_strdup( const char *str )
{
    char *result = NULL;

    if( str == NULL )
    {
        DebugBreak();
        return NULL;
    }

    result = (char *)this->malloc( (ULONG)strlen(str)+1 );
    strcpy(result, str);

    return result;
}

char *otlkcon_memory::_strdupMore( void *parentObj, const char *str )
{
    char *result = NULL;

    if( str == NULL  )
    {
        DebugBreak();
        return NULL;
    }

    result = (char *)this->mallocMore( parentObj, (ULONG)strlen(str)+1 );
    strcpy(result, str);

    return result;
}

wchar_t *otlkcon_memory::w_strdup( const wchar_t *str )
{
	wchar_t *result = NULL;

	if( str == NULL )
	{
		DebugBreak();
		return NULL;
	}

	result = (wchar_t *)this->malloc( (ULONG)(wcslen(str)+1)*sizeof(wchar_t));
	wcscpy(result, str);

	return result;
}

wchar_t *otlkcon_memory::w_strdupMore( void *parentObj, const wchar_t *str )
{
	wchar_t *result = NULL;

	if( str == NULL  )
	{
		DebugBreak();
		return NULL;
	}

	result = (wchar_t *)this->mallocMore( parentObj, (ULONG)(wcslen(str)+1)*sizeof(wchar_t) );
	wcscpy(result, str);

	return result;
}

void *otlkcon_memory::pMalloc( ULONG size )
{
//in order to catch memory corruption we use MAPI's routines

#ifdef USE_POOL_MEMORY
	void *ret = boost::singleton_pool<otlkcon_tag,1>::ordered_malloc( size );
#else
	void *ret = this->malloc(size);
#endif
    memset(ret,0,size);

    return ret;
}

void otlkcon_memory::pFree( void *buff )
{
#ifdef USE_POOL_MEMORY
    boost::singleton_pool<otlkcon_tag,1>::ordered_free( buff );
#else
	this->free(buff);
#endif
    return;
}

char *otlkcon_memory::pStrdup( const char *str )
{
    char *result = NULL;

    if( str == NULL )
    {
        DebugBreak();
        return NULL;
    }

    result = (char *)this->pMalloc( (ULONG)strlen(str)+1 );
    strcpy(result, str);

    return result;
}

wchar_t *otlkcon_memory::pWcsdup( const wchar_t *str )
{
    wchar_t *result = NULL;

    if( str == NULL )
    {
        DebugBreak();
        return NULL;
    }

    result = (wchar_t *)this->pMalloc( (ULONG)((wcslen(str)+1)*sizeof(wchar_t)) );
    wcscpy(result, str);

    return result;
}

LPSPropValue otlkcon_memory::propdup(ULONG cValues, LPSPropValue lpSrc)
{
	LPSPropValue lpResult = NULL;
	ULONG cb = 0;
	HRESULT hResult = ScCountProps(cValues, lpSrc, &cb);
	if(SUCCEEDED(hResult))
	{
		lpResult = (LPSPropValue)malloc(cb);
		if(NULL != lpResult)
		{
			ULONG cbCopy = 0;
			hResult = ScCopyProps(cValues, lpSrc, lpResult, &cbCopy);
			if(FAILED(hResult) || cb != cbCopy)
			{
				free(lpResult);
				lpResult = NULL;
			} // if
		} // if
	} // if
	return lpResult;
}

LPBYTE otlkcon_memory::bindup(ULONG cb, LPBYTE lpb)
{
	LPBYTE lpResult = NULL;

	lpResult = (LPBYTE)malloc(cb);
	if(NULL != lpResult)
	{
		memcpy(lpResult, lpb, cb);
	} // if
	return lpResult;
}
